package cc.magicjson.example.demo.concurrent;

import cc.magicjson.example.demo.collection.MergeDataItems;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@State(Scope.Benchmark)
public class MergeAndGroupListsBenchmark {
    @Param({"100", "1000", "10000"})
    private int listSize;

    private List<DataItem> list1;
    private List<DataItem> list2;

    @Setup(Level.Iteration)
    public void setup() {
        list1 = generateList(listSize);
        list2 = generateList(listSize);
    }

    @TearDown(Level.Iteration)
    public void tearDown() {
        list1 = null;
        list2 = null;
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void testOriginalMethod() {
        MergeDataItems.mergeAndGroupLists(list1, list2, DataItem::getTimestamp, (item1, item2) -> {
            DataItem result = new DataItem(item1.getTimestamp(), item1.getData());
            result.setData(result.getData() + "-" + item2.getData());
            return result;
        });
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void testOptimizedMethod() {
        MergeDataItemsOp.mergeAndGroupLists(list1, list2, DataItem::getTimestamp
                , 	(item1, item2) -> {
                    DataItem result = new DataItem(item1.getTimestamp(), item1.getData());
                    result.setData(result.getData() + "-" + item2.getData());
                    return result;
                }
        );

    }

    private List<DataItem> generateList(int size) {
        List<DataItem> list = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            list.add(new DataItem("2023-01-01 10:00", "A"));
        }
        return list;
    }


    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
                .include(MergeAndGroupListsBenchmark.class.getName())
//                .mode(Mode.Throughput)
//                .timeUnit(TimeUnit.MILLISECONDS)
                .warmupIterations(3)
                .forks(1)
                .build();
        new Runner(options).run();
    }

}